/*
 * AdminApplication.java
 *
 * Created on March 27, 2007, 2:06 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.admin;

import java.net.URL;
import java.util.Iterator;
import org.atomojo.app.App;
import org.atomojo.app.Storage;
import org.atomojo.app.WebComponent;
import org.atomojo.app.db.DB;
import org.infoset.xml.ElementEnd;
import org.infoset.xml.Item;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.Validity;
import org.infoset.xml.XMLException;
import org.infoset.xml.filter.ItemFilter;
import org.infoset.xml.xerces.XMLSchemaValidationFilter;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.Reference;
import org.restlet.routing.Filter;
import org.restlet.routing.Router;
import org.restlet.routing.Template;

/**
 *
 * @author alex
 */
public class AdminApplication extends Application {
   
   static ItemDestination createAdminDocumentDestination(ItemDestination end,final Name documentElement) 
      throws XMLException
   {
      Name [] names = { documentElement };
      return createAdminDocumentDestination(end,names);
   }
   static ItemDestination createAdminDocumentDestination(ItemDestination end,final Name [] names) 
      throws XMLException
   {
      final XMLSchemaValidationFilter validate = new XMLSchemaValidationFilter();
      URL adminXSD = AdminXML.class.getResource("admin.xsd");
      if (adminXSD==null) {
         throw new RuntimeException("Cannot find admin.xsd relative to class path.");
      }
      validate.addNamespaceMap(AdminXML.NAMESPACE,adminXSD);
      ItemFilter checkValidity = new ItemFilter() {
         ItemDestination output;
         int level = -1;
         public void send(Item item) 
            throws XMLException
         {
            switch (item.getType()) {
               case DocumentItem:
                  level = -1;
                  break;
               case ElementItem:
                  level++;
                  break;
               case ElementEndItem:
                  level--;
                  ElementEnd end = (ElementEnd)item;
                  if (level<0) {
                     if (end.getValidity()!=Validity.VALID) {
                        StringBuilder builder = new StringBuilder();
                        Iterator errors = validate.getErrors();
                        while (errors.hasNext()) {
                           builder.append("\n");
                           builder.append(errors.next().toString());
                        }
                        throw new XMLException("Element "+end.getName()+" is not valid:"+builder.toString());
                     }
                     Name name = end.getName();
                     boolean found = false;
                     for (int i=0; !found && i<names.length; i++) {
                        if (names[i].equals(name)) {
                           found = true;
                        }
                     }
                     if (!found) {
                        throw new XMLException("Unexpected document element "+name);
                     }
                  }
                  break;
            }
            output.send(item);
         }
         public void attach(ItemDestination output) {
            this.output = output;
         }
      };
      validate.attach(checkValidity);
      checkValidity.attach(end);
      return validate;
   }
   
   public static String getStringAttribute(Request request, String name, String defaultValue)
   {
      Object obj = request.getAttributes().get(name);
      return obj==null ? defaultValue : obj.toString();
   }
   DB db;
   Storage storage;
   Reference resourceBase;
   
   /** Creates a new instance of AdminApplication */
   public AdminApplication(Context context,DB db,Storage storage,Reference resourceBase) {
      super(context);
      this.db = db;
      this.storage = storage;
      this.resourceBase = resourceBase;
      getTunnelService().setEnabled(false);
      getContext().getAttributes().put(WebComponent.ATOMOJO_TMP_DIR,context.getAttributes().get(WebComponent.ATOMOJO_TMP_DIR));
   }
   
   @Override
   public Restlet createRoot() {
      Filter attFilter = new Filter(getContext()) {
         protected int beforeHandle(Request request,Response response)
         {
            request.getAttributes().put(App.DB_ATTR,db);
            request.getAttributes().put(App.STORAGE_ATTR,storage);
            request.getAttributes().put(App.RESOURCE_BASE_ATTR,resourceBase);
            return Filter.CONTINUE;
         }
      };
      Router router = new Router(getContext());
      attFilter.setNext(router);
      router.setDefaultMatchingMode(Template.MODE_STARTS_WITH);
      router.attach("/users",new UserApplication(getContext(),db));
      router.attach("/sync",new SyncApplication(getContext(),db,storage));
      router.attach("/backup",BackupResource.class);
      router.attach("/backup.zip",BackupResource.class);
      router.attach("/restore",RestoreResource.class);
      router.attach("/derby",new DerbyApplication(getContext(),db,storage));
      router.attach("/restart",RestartResource.class).getTemplate().setMatchingMode(Template.MODE_EQUALS);
      Application storageAdmin = storage.getAdministration();
      if (storageAdmin!=null) {
         router.attach("/storage",storageAdmin);
      }
      return attFilter;
   }
}
